Course Contents

  1. 2022.12.07: Introduction: About the course [lead by TK]
    • An introduction to open and public data, and data science
  2. 2022-12-14: Exploratory Data Analysis (EDA) 1 [lead by hs]
    • R Basics with RStudio and/or RStudio.cloud; Toy Data
  3. 2022-12-21: Exploratory Data Analysis (EDA) 2 [lead by hs]
    • R Markdown, tidyverse I: dplyr; gapminder
  4. **2023-01-11: Exploratory Data Analysis (EDA) 3 [lead by hs]
    • tidyverseII: readr, ggplot2; Public Data, WDI, WIR, etc**
  5. 2023-01-18: Exploratory Data Analysis (EDA) 4 [lead by hs]
    • tidyverse III: tidyr, etc.; WDI, WIR, etc
  6. 2023-01-25: Exploratory Data Analysis (EDA) 5 [lead by hs]
    • tidyverse IV; WDI, WIR, etc
  7. 2023-02-01: Introduction to PPDAC
    • Problem-Plan-Data-Analysis-Conclusion Cycle: [lead by TK]
  8. 2023-02-08: Model building I [lead by TK]
    • Collecting and visualizing data and Introduction to WDI
      (World Development Indicators by World Bank)
  9. 2023-02-15: Model building II [lead by TK]
    • Analyzing data and communications
  10. 2023-02-22: Project Presentation

1 Exploratory Data Analysis (EDA) I

2 Exploratory Data Analysis II

3 Exploratory Data Analysis III

3.1 Importing Public Data, WDI

3.1.1 Reviews and Previews

library(tidyverse)
library(gapminder)
library(maps)
library(WDI)

(df <- gapminder)

asean <- c("Brunei", "Cambodia", "Laos", "Myanmar", "Philippines", "Indonesia", "Malaysia", "Singapore")
df %>% filter(country %in% asean) %>%
  ggplot(aes(x = year, y = gdpPercap, col = country)) + geom_line()


df %>% filter(country %in% asean) %>%
  ggplot(aes(x = gdpPercap, y = lifeExp, col = country)) + geom_point()


df %>% filter(country %in% asean) %>%
  ggplot(aes(x = gdpPercap, y = lifeExp, col = country)) + 
  geom_point() + coord_trans(x = "log10", y = "identity")

\(\log_{10}{100}\) = 2, \(\log_{10}{1000}\) = 3, \(\log_{10}{10000}\) = 4




3.1.1.1 World Bank: World Development Indicators (WDI)

  • SP.DYN.LE00.IN: Life expectancy at birth, total (years)
  • NY.GDP.PCAP.KD: GDP per capita (constant 2015 US$)
  • SP.POP.TOTL: Population, total
df_wdi <- WDI(
  country = "all", 
  indicator = c(lifeExp = "SP.DYN.LE00.IN", pop = "SP.POP.TOTL", gdpPercap = "NY.GDP.PCAP.KD")
)

df_wdi

df_wdi_extra <- WDI(
  country = "all", 
  indicator = c(lifeExp = "SP.DYN.LE00.IN", pop = "SP.POP.TOTL", gdpPercap = "NY.GDP.PCAP.KD"), 
  extra = TRUE
)

df_wdi_extra

3.1.2 Exploratory Data Analysis

3.1.2.1 What is EDA (Posit Primers: Visualise Data)

  1. EDA is an iterative cycle that helps you understand what your data says. When you do EDA, you:

  2. Generate questions about your data

  3. Search for answers by visualising, transforming, and/or modeling your data

Use what you learn to refine your questions and/or generate new questions

EDA is an important part of any data analysis. You can use EDA to make discoveries about the world; or you can use EDA to ensure the quality of your data, asking questions about whether the data meets your standards or not.


3.1.3 Open and Public Data, World Bank

3.1.3.1 Open Government Data Toolkit: Open Data Defined

The term Open Data has a very precise meaning. Data or content is open if anyone is free to use, re-use or redistribute it, subject at most to measures that preserve provenance and openness.

  1. The data must be legally open, which means they must be placed in the public domain or under liberal terms of use with minimal restrictions.
  2. The data must be technically open, which means they must be published in electronic formats that are machine readable and non-proprietary, so that anyone can access and use the data using common, freely available software tools. Data must also be publicly available and accessible on a public server, without password or firewall restrictions. To make Open Data easier to find, most organizations create and manage Open Data catalogs.

3.1.4 World Bank: WDI - World Development Indicaters

  • World Bank: https://www.worldbank.org
  • Who we are:
    • To end extreme poverty: By reducing the share of the global population that lives in extreme poverty to 3 percent by 2030.
    • To promote shared prosperity: By increasing the incomes of the poorest 40 percent of people in every country.
  • World Bank Open Data: https://data.worldbank.org
    • Data Bank, World Development Indicators, etc.
  • World Development Indicators (WDI) : the World Bank’s premier compilation of cross-country comparable data on development; 1400 time series indicators
    • Themes: Poverty and Inequality, People, Environment, Economy, States and Markets, Global Links
    • Open Data & DataBank: Explore data, Query database
    • Bulk Download: Excel, CSV
    • API Documentation

3.1.5 R Package WDI

  • WDI: World Development Indicators and Other World Bank Data
  • Search and download data from over 40 databases hosted by the World Bank, including the World Development Indicators (‘WDI’), International Debt Statistics, Doing Business, Human Capital Index, and Sub-national Poverty indicators.
  • Version: 2.7.4
  • Materials: README - usage
    • NEWS - version history
  • Published: 2021-04-06
  • README: https://cran.r-project.org/web/packages/WDI/readme/README.html
  • Reference manual: WDI.pdf

3.1.6 Function WDI

  • Usage
WDI(country = "all",
    indicator = "NY.GDP.PCAP.KD",
    start = 1960,
    end = 2020,
    extra = FALSE,
    cache = NULL)
  • Arguments See Help!
    • country: Vector of countries (ISO-2 character codes, e.g. “BR”, “US”, “CA”, or “all”)
    • indicator: If you supply a named vector, the indicators will be automatically renamed: c('women_private_sector' = 'BI.PWK.PRVS.FE.ZS')

3.1.7 Function WDIsearch

library(WDI)
WDIsearch(string = "NY.GDP.PCAP.KD", 
          field = "indicator", cache = NULL)

WDIsearch(string = "population", 
          field = "name", short=FALSE, cache = NULL)

WDIsearch(string = "NY.GDP.PCAP.KD", 
  field = "indicator", short = FALSE, cache = NULL)
WDIsearch(string = "gdp", 
  field = "name", short = TRUE, cache = NULL) 

3.1.8 Use cash

WDIbulk downloads the zip file of Bulk Downloads in WDI site , it is a list containing 6 data frames: Data, Country, Series, Country-Series, Series-Time, FootNote.

timeout: integer maximum number of seconds to wait for download

wdi <- WDIbulk(timeout = 600)

3.1.8.1 Bulk Downloads: Data

wdi$Data  

3.1.8.2 Bulk Downloads: Country

wdi$Country  

3.1.8.3 Bulk Downloads: Series

wdi$Series 

3.1.8.4 Bulk Downloads: Country-Series

wdi$`Country-Series`  

3.1.8.5 Bulk Downloads: Series-Time

wdi$`Series-Time`  

3.1.8.6 Bulk Downloads: Footnote

wdi$FootNote 

3.1.9 WDIcache

Download an updated list of available WDI indicators from the World Bank website. Returns a list for use in the WDIsearch function.

wdi_cache <- WDIcache()

Downloading all series information from the World Bank website can take time. The WDI package ships with a local data object with information on all the series available on 2012-06-18. You can update this database by retrieving a new list using WDIcache, and then feeding the resulting object to WDIsearch via the cache argument.


wdi_cache
$series

$country
NA

3.1.10 WDI_data

List of 2 data frames

The first character matrix includes a full list of WDI series. This list is updated semi-regularly. Users can refresh the list manually using the ‘WDIcache()’ function and search in the updated list using the ‘cache’ argument.

glimpse(WDI_data)
List of 2
 $ series :'data.frame':    20238 obs. of  5 variables:
  ..$ indicator         : chr [1:20238] "1.0.HCount.1.90usd" "1.0.HCount.2.5usd" "1.0.HCount.Mid10to50" "1.0.HCount.Ofcl" ...
  ..$ name              : chr [1:20238] "Poverty Headcount ($1.90 a day)" "Poverty Headcount ($2.50 a day)" "Middle Class ($10-50 a day) Headcount" "Official Moderate Poverty Rate-National" ...
  ..$ description       : chr [1:20238] "The poverty headcount index measures the proportion of the population with daily per capita income (in 2011 PPP"| __truncated__ "The poverty headcount index measures the proportion of the population with daily per capita income (in 2005 PPP"| __truncated__ "The poverty headcount index measures the proportion of the population with daily per capita income (in 2005 PPP"| __truncated__ "The poverty headcount index measures the proportion of the population with daily per capita income below the of"| __truncated__ ...
  ..$ sourceDatabase    : chr [1:20238] "LAC Equity Lab" "LAC Equity Lab" "LAC Equity Lab" "LAC Equity Lab" ...
  ..$ sourceOrganization: chr [1:20238] "LAC Equity Lab tabulations of SEDLAC (CEDLAS and the World Bank)." "LAC Equity Lab tabulations of SEDLAC (CEDLAS and the World Bank)." "LAC Equity Lab tabulations of SEDLAC (CEDLAS and the World Bank)." "LAC Equity Lab tabulations of data from National Statistical Offices." ...
 $ country:'data.frame':    299 obs. of  9 variables:
  ..$ iso3c    : chr [1:299] "ABW" "AFE" "AFG" "AFR" ...
  ..$ iso2c    : chr [1:299] "AW" "ZH" "AF" "A9" ...
  ..$ country  : chr [1:299] "Aruba" "Africa Eastern and Southern" "Afghanistan" "Africa" ...
  ..$ region   : chr [1:299] "Latin America & Caribbean" "Aggregates" "South Asia" "Aggregates" ...
  ..$ capital  : chr [1:299] "Oranjestad" "" "Kabul" "" ...
  ..$ longitude: chr [1:299] "-70.0167" "" "69.1761" "" ...
  ..$ latitude : chr [1:299] "12.5167" "" "34.5228" "" ...
  ..$ income   : chr [1:299] "High income" "Aggregates" "Low income" "Aggregates" ...
  ..$ lending  : chr [1:299] "Not classified" "Aggregates" "IDA" "Aggregates" ...

WDI_data$series

WDI_data$country
WDI_data$country  %>% filter(country == "Japan")

WDIsearch(string = "gdp", 
  field = "name", short = FALSE, cache = wdi_cache) 

3.1.11 World Development Indicators - Summary

Find indicators:

  1. WDIsearch(string = "gdp", field = "name", short = FALSE, cache = NULL)
  • WDIsearch(string = "gdp", field = "name", short = FALSE, cache = wdi_cache)
  • WDIsearch(string = "NY.GDP.PCAP.KD", field = "indicator", short = FALSE, cache = NULL)
  1. WDI: Data Themes
  2. Browse by Indicators: https://data.worldbank.org/indicator
    • Featured Indicators or All Indicators
    • Obtain the indicator from the detail or the URL

3.1.11.1 Example: CO2 emissions (metric tons per capita)

WDIsearch(string = "EN.ATM.CO2E.PC", field = "indicator", 
          short = FALSE, cache = wdi_cache)
WDIsearch(string = "EN.ATM.CO2E.PC", field = "indicator", 
          short = FALSE, cache = wdi_cache) %>% pull(description)
  • Source: Climate Watch. 2020. GHG Emissions. Washington, DC: World Resources Institute. Available at: climatewatchdata.org/ghg-emissions. See SP.POP.TOTL for the denominator’s source.

co2pcap <- WDI(country = "all", indicator = "EN.ATM.CO2E.PC", start = 1960, end = NULL, extra = TRUE, cache = wdi_cache)
co2pcap

co2pcap %>% filter(country %in% c("World", "Japan", "United States", "China")) %>%
  ggplot(aes(x = year, y = EN.ATM.CO2E.PC, color = country)) + 
  geom_point() + geom_line()


co2pcap %>% filter(!is.na(EN.ATM.CO2E.PC)) %>% pull(year) %>% summary()
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   1990    1997    2005    2005    2012    2019 

co2pcap %>% filter(country %in% c("World", "Japan", "United States", "China"), year %in% 1990:2019) %>%
  ggplot(aes(x = year, y = EN.ATM.CO2E.PC, color = country)) + 
  geom_point() + geom_line()


co2pcap %>% 
  filter(income != "Aggregates", year == 2019) %>%
  ggplot(aes(x = income, y = EN.ATM.CO2E.PC, fill = income)) + 
  geom_boxplot()


co2pcap %>% 
  filter(income != "Aggregates", year == 2019, !is.na(EN.ATM.CO2E.PC)) %>%
  ggplot(aes(x = income, y = EN.ATM.CO2E.PC, fill = income)) + 
  geom_boxplot()


co2pcap %>% 
  filter(income != "Aggregates", year == 2019, !is.na(EN.ATM.CO2E.PC)) %>%
  group_by(income) %>%
  summarize(min = min(EN.ATM.CO2E.PC), med = median(EN.ATM.CO2E.PC), max = max(EN.ATM.CO2E.PC), IQR = IQR(EN.ATM.CO2E.PC), n = n())

co2pcap %>% 
  filter(income != "Aggregates", year == 2019, !is.na(EN.ATM.CO2E.PC)) %>%
  filter(!income %in% c("High income", "Low income", "Lower middle income", "Upper middle income"))
co2pcap %>% 
  filter(income != "Aggregates", year == 2019) %>%
  filter(income == "Not classified")


co2pcap %>% distinct(country)

world_map %>% distinct(region)
world_map0 <- world_map %>% 
  mutate(region = case_when(region == "Macedonia" ~ "North Macedonia",
                            region == "Ivory Coast"  ~ "Cote d'Ivoire",
                            region == "Democratic Republic of the Congo"  ~ "Congo, Dem. Rep.",
                            region == "Republic of Congo" ~  "Congo, Rep.",
                            region == "UK" ~  "United Kingdom",
                            region == "USA" ~  "United States",
                            region == "Laos" ~  "Lao PDR",
                            region == "Slovakia" ~  "Slovak Republic",
                            region == "Saint Lucia" ~  "St. Lucia",
                            region == "Kyrgyzstan"  ~  "Kyrgyz Republic",
                            region == "Micronesia" ~ "Micronesia, Fed. Sts.",
                            region == "Swaziland"  ~ "Eswatini", 
                            region == "Virgin Islands"  ~ "Virgin Islands (U.S.)", 
                            region == "Russia" ~ "Russian Federation", 
                            region == "Egypt" ~ "Egypt, Arab Rep.",
                            region == "South Korea" ~ "Korea, Rep.",
                            region == "North Korea" ~ "Korea, Dem. People's Rep.",
                            region == "Iran" ~ "Iran, Islamic Rep.",
                            region == "Brunei" ~ "Brunei Darussalam",
                            region == "Venezuela" ~ "Venezuela, RB",
                            region == "Yemen" ~ "Yemen, Rep.",
                            region == "Bahamas" ~ "Bahamas, The",
                            region == "Syria" ~ "Syrian Arab Republic",
                            region == "Turkey" ~ "Turkiye",
                            region == "Cape Verde" ~ "Cabo Verde",
                            region == "Gambia" ~ "Gambia, The",
                            region == "Czech Republic" ~ "Czechia",
                            TRUE ~ region))

co2pcap %>% filter(income != "Aggregates", year == 2019) %>% 
  anti_join(world_map0, by = c("country"="region"))

world_map0 %>% anti_join(co2pcap, by = c("region"="country")) %>% distinct(region) %>% arrange(region)

world_map0 %>% left_join(iso3166, by = c("region" = "ISOname")) %>%
  filter(is.na(a2)) %>% distinct(region)
world_map <- map_data("world")
co2pcap %>% filter(income != "Aggregates", year == 2019) %>%
  anti_join(world_map, by = c("country"="region"))
world_map %>% distinct(region)

3.2 Data Visualization and `ggplot2’

3.2.1 Learning Resouces

  • Posit Primers:
    • Visualize Data: Learn how to use ggplot2 to make any type of plot with your data. Then learn the best ways to visualize patterns within values and relationships between variables.
  • r4ds: Data Visualization

3.2.2 Exploratory Data Analysis

3.2.2.1 What is EDA?

EDA is an iterative cycle that helps you understand what your data says. When you do EDA, you:

  1. Generate questions about your data

  2. Search for answers by visualising, transforming, and/or modeling your data

  3. Use what you learn to refine your questions and/or generate new questions

EDA is an important part of any data analysis. You can use EDA to make discoveries about the world; or you can use EDA to ensure the quality of your data, asking questions about whether the data meets your standards or not.


3.2.2.2 Two useful questions

There is no rule about which questions you should ask to guide your research. However, two types of questions will always be useful for making discoveries within your data. You can loosely word these questions as:

  1. What type of variation occurs within my variables?
  2. What type of covariation occurs between my variables?

The rest of this tutorial will look at these two questions. To make the discussion easier, let’s define some terms…


3.2.3 Data Visualization

3.2.4 ggplot2 Basics

visualization


3.2.5 Example: World Inequility Report - WIR2022

library(readxl)
url_summary <- "https://wir2022.wid.world/www-site/uploads/2022/03/WIR2022TablesFigures-Summary.xlsx"
download.file(url = url_summary, destfile = "data/WIR2022s.xlsx") 
excel_sheets("data/WIR2022s.xlsx")

3.2.6 F14: Global carbon inequality, 2019. Group contribution to world emissions (%)

Note that the sheet name of F14 has period at the end.

df_f14 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F14.")
df_f14
  • \n for line break in the title.

3.2.6.1 Categorical vs Continuous Value

df_f14 %>% 
  ggplot(aes(x = Group, y = Share)) +
  geom_col()


df_f14 %>% 
  ggplot(aes(x = Group, y = Share)) +
  geom_col(width = 0.5, fill = scales::hue_pal()(1)[1]) + 
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  labs(title = "Figure 14. Global carbon inequality, \n2019 Group contribution to world emissions (%)", 
       x = "", y = "Share of world emissions (%)")


3.2.6.2 Memo

  • width = 0.5: width of bars
  • fill = scales::hue_pal()(1)[1]): hue scale
  • scale_y_continuous(labels = scales::percent_format(accuracy = 1)): percent format
    • if accuracy = 0.1, we have 10.0% etc.
  • labs(title = "Figure 14. Global carbon inequality, \n2019 Group contribution to world emissions (%)", x = "", y = "Share of world emissions (%)")
    • title = ““: \n is for line feed
    • x, y: labels of x-axis and y-axis

3.2.7 F12: Female share in global labor incomes, 1990-2020

df_f12 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F12")
New names:
df_f12

df_f12 %>% 
  select(year = "Data needs to be updated", value = ...2) %>%
  filter(!is.na(year)) %>%
  ggplot(aes(x = year, y = value)) +
  geom_col(width = 0.5, fill = scales::hue_pal()(2)[2])


df_f12 %>% 
  select(year = "Data needs to be updated", value = ...2) %>%
  filter(!is.na(year)) %>%
  ggplot(aes(x = year, y = value)) +
  geom_col(width = 0.5, fill = scales::hue_pal()(2)[2]) +
  geom_hline(yintercept = 0.5, linetype = 2, colour = scales::hue_pal()(2)[1]) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  labs(title = "Figure 12. Female share in global labor incomes, 1990-2020", 
        x = "", y = "") +
  annotate("text", x = 1, y = 0.48, label = "Gender parity", size = 3) +
  annotate("text", x = 5.2, y = 0.47, label = stringr::str_wrap("Women make only 35% of global labor incomes, men make the remaining  65%.", width = 40), size = 3)

3.2.8 F1: Global income and wealth inequality, 2021

df_f1 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F1")
New names:
df_f1

df_f1_rev %>%
  ggplot(aes(x = cat, y = value, fill = group)) +
  geom_col(position = "dodge")

3.2.9 References of ggplot2

3.2.9.1 RStudio Primers: See References in Moodle at the bottom

  1. Visualize Data
  • Exploratory Data Analysis
  • Bar Charts
  • Histograms
  • Boxplots and Counts
  • Scatterplots
  • Line Plots
  • Overplotting and Big Data
  • Customize Your Plots

3.3 The Week Three Assignment (in Moodle)

WDI and ggplot2

  • Create an R Notebook of a Data Analysis containing the following and submit the rendered HTML file (eg. a3_123456.nb.html)
    1. create an R Notebook using the R Notebook Template in Moodle, save as a3_123456.Rmd,
    2. write your name and ID and the contents,
    3. run each code block,
    4. preview to create a3_123456.nb.html,
    5. submit a3_123456.nb.html to Moodle.
  1. Choose at least one indicator of WDI

    • Information of the data: Name, Indicator, Description, Source, etc.
    • Download the data with WDI
    • Explain why you chose the indicator
    • List questions you want to study

  1. Explore the data using visualization

  2. Observations and difficulties encountered.

Due: 2023-01-16 23:59:00. Submit your R Notebook file in Moodle (The Third Assignment). Due on Monday!


LS0tCnRpdGxlOiAnUUFMTDQwMTogRGF0YSBBbmFseXNpcyBmb3IgUmVzZWFyY2hlcnMnCm91dHB1dDoKICBpb3NsaWRlc19wcmVzZW50YXRpb246IAogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICB3aWRlc2NyZWVuOiB5ZXMKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogIGJlYW1lcl9wcmVzZW50YXRpb246IGRlZmF1bHQKICBwZGZfZG9jdW1lbnQ6CiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogIGh0bWxfbm90ZWJvb2s6CiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwotLS0KCiMjIENvdXJzZSBDb250ZW50cyB7LX0KCjEuIDIwMjIuMTIuMDc6IEludHJvZHVjdGlvbjogQWJvdXQgdGhlIGNvdXJzZSBbbGVhZCBieSBUS10KICAgIC0gQW4gaW50cm9kdWN0aW9uIHRvIG9wZW4gYW5kIHB1YmxpYyBkYXRhLCBhbmQgZGF0YSBzY2llbmNlCjIuIDIwMjItMTItMTQ6IEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgKEVEQSkgMSBbbGVhZCBieSBoc10gIAogICAgLSBSIEJhc2ljcyB3aXRoIFJTdHVkaW8gYW5kL29yIFJTdHVkaW8uY2xvdWQ7IFRveSBEYXRhCjMuIDIwMjItMTItMjE6IEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgKEVEQSkgMiBbbGVhZCBieSBoc10gICAKICAgIC0gUiBNYXJrZG93biwgYHRpZHl2ZXJzZWAgSTogYGRwbHlyYDsgYGdhcG1pbmRlcmAKNC4gKioyMDIzLTAxLTExOiBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzIChFREEpIDMgW2xlYWQgYnkgaHNdICAKICAgIC0gYHRpZHl2ZXJzZWBJSTogYHJlYWRyYCwgYGdncGxvdDJgOyBQdWJsaWMgRGF0YSwgV0RJLCBXSVIsIGV0YyoqCjUuIDIwMjMtMDEtMTg6IEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgKEVEQSkgNCBbbGVhZCBieSBoc10gIAogICAgLSBgdGlkeXZlcnNlYCBJSUk6IGB0aWR5cmAsIGV0Yy47IFdESSwgV0lSLCBldGMKNi4gMjAyMy0wMS0yNTogRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyAoRURBKSA1IFtsZWFkIGJ5IGhzXSAgCiAgICAtIGB0aWR5dmVyc2VgIElWOyBXREksIFdJUiwgZXRjCjcuIDIwMjMtMDItMDE6IEludHJvZHVjdGlvbiB0byBQUERBQyAgICAgICAgIAogICAgLSBQcm9ibGVtLVBsYW4tRGF0YS1BbmFseXNpcy1Db25jbHVzaW9uIEN5Y2xlOiBbbGVhZCBieSBUS10KOC4gMjAyMy0wMi0wODogTW9kZWwgYnVpbGRpbmcgSSBbbGVhZCBieSBUS10gICAgCiAgICAtIENvbGxlY3RpbmcgYW5kIHZpc3VhbGl6aW5nIGRhdGEgYW5kIEludHJvZHVjdGlvbiB0byBXREkgIAogICAgICAgICAoV29ybGQgRGV2ZWxvcG1lbnQgSW5kaWNhdG9ycyBieSBXb3JsZCBCYW5rKQo5LiAyMDIzLTAyLTE1OiBNb2RlbCBidWlsZGluZyBJSSBbbGVhZCBieSBUS10gICAgCiAgICAtIEFuYWx5emluZyBkYXRhIGFuZCBjb21tdW5pY2F0aW9ucwoxMC4gMjAyMy0wMi0yMjogUHJvamVjdCBQcmVzZW50YXRpb24KCgojIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgKEVEQSkgSQoKCiMgRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyBJSQoKCiMgRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyBJSUkgIAoKIyMgSW1wb3J0aW5nIFB1YmxpYyBEYXRhLCBXREkKCiMjIyBSZXZpZXdzIGFuZCBQcmV2aWV3cwoKYGBge3IgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ2FwbWluZGVyKQpsaWJyYXJ5KG1hcHMpCmxpYnJhcnkoV0RJKQpgYGAKCi0tLQoKYGBge3J9CihkZiA8LSBnYXBtaW5kZXIpCmBgYAoKLS0tCgpgYGB7cn0KYXNlYW4gPC0gYygiQnJ1bmVpIiwgIkNhbWJvZGlhIiwgIkxhb3MiLCAiTXlhbm1hciIsICJQaGlsaXBwaW5lcyIsICJJbmRvbmVzaWEiLCAiTWFsYXlzaWEiLCAiU2luZ2Fwb3JlIikKZGYgJT4lIGZpbHRlcihjb3VudHJ5ICVpbiUgYXNlYW4pICU+JQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBnZHBQZXJjYXAsIGNvbCA9IGNvdW50cnkpKSArIGdlb21fbGluZSgpCmBgYAoKLS0tCmBgYHtyfQpkZiAlPiUgZmlsdGVyKGNvdW50cnkgJWluJSBhc2VhbikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZ2RwUGVyY2FwLCB5ID0gbGlmZUV4cCwgY29sID0gY291bnRyeSkpICsgZ2VvbV9wb2ludCgpCmBgYAoKLS0tCgpgYGB7cn0KZGYgJT4lIGZpbHRlcihjb3VudHJ5ICVpbiUgYXNlYW4pICU+JQogIGdncGxvdChhZXMoeCA9IGdkcFBlcmNhcCwgeSA9IGxpZmVFeHAsIGNvbCA9IGNvdW50cnkpKSArIAogIGdlb21fcG9pbnQoKSArIGNvb3JkX3RyYW5zKHggPSAibG9nMTAiLCB5ID0gImlkZW50aXR5IikKYGBgCiRcbG9nX3sxMH17MTAwfSQgPSBgciBsb2cxMCgxMDApYCwgJFxsb2dfezEwfXsxMDAwfSQgPSBgciBsb2cxMCgxMDAwKWAsICRcbG9nX3sxMH17MTAwMDB9JCA9IGByIGxvZzEwKDEwMDAwKWAKCjwhLS0gJDEwXnsyLjV9JCA9IGByIHNxcnQoMTApXns1fWAsICQxMF57M30kID0gYHIgMTBeezN9YCwgJDEwXnszLjV9JCA9IGByIHNxcnQoMTApXjdgLCAgLS0+Cgo8IS0tICQxMF57NH0kID0gYHIgMTBeNGAsICQxMF57NC41fSQgPSBgciBzcXJ0KDEwKV45YC4gLS0+CgotLS0KCmBgYHtyIGVjaG89RkFMU0V9CmxpYnJhcnkoZ2dyZXBlbCkKZGYyMDA3IDwtIGRmICU+JSBmaWx0ZXIoY291bnRyeSAlaW4lIGFzZWFuLCB5ZWFyID09IDIwMDcpCmRmICU+JSBmaWx0ZXIoY291bnRyeSAlaW4lIGFzZWFuKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBnZHBQZXJjYXAsIHkgPSBsaWZlRXhwLCBjb2wgPSBjb3VudHJ5KSkrIAogIGdlb21fbGluZSgpICsgZ2VvbV9sYWJlbF9yZXBlbChkYXRhID0gZGYyMDA3LCBhZXMobGFiZWwgPSBjb3VudHJ5KSkgKyBnZW9tX3BvaW50KCkgICsKICBjb29yZF90cmFucyh4ID0gImxvZzEwIiwgeSA9ICJpZGVudGl0eSIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDEsIGhqdXN0PTEpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBsYWJzKHRpdGxlID0gIkxpZmUgRXhwZWN0YW5jeSB2cyBHRFAgUGVyIENhcGl0YSBvZiBBU0VBTiBDb3VudHJpZXMiLAogICAgICAgc3VidGl0bGUgPSAiRGF0YTogZ2FwbWluZGVyIHBhY2thZ2UiLCB4ID0gIkdEUCBwZXIgQ2FwaXRhIiwgeSA9ICJMaWZlIEV4cGVjdGFuY3kiKQpgYGAKCi0tLQoKYGBge3IgZWNobz1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkobWFwcykKd29ybGRfbWFwIDwtIG1hcF9kYXRhKCJ3b3JsZCIpCmRmICU+JQogIGdncGxvdChhZXMobWFwX2lkID0gY291bnRyeSkpICsgCiAgZ2VvbV9tYXAoYWVzKGZpbGwgPSBnZHBQZXJjYXApLCBtYXAgPSB3b3JsZF9tYXApICsgZXhwYW5kX2xpbWl0cyh4ID0gd29ybGRfbWFwJGxvbmcsIHkgPSB3b3JsZF9tYXAkbGF0KSArCiAgbGFicyh0aXRsZSA9ICJHYXBtaW5kZXIgUGFja2FnZSBEYXRhIiwgc3VidGl0bGU9IldvcmxkIE1hcCBvZiBHRFAgcGVyIENhcGl0YSBEYXRhIikKYGBgCgotLS0KCiMjIyMgV29ybGQgQmFuazogV29ybGQgRGV2ZWxvcG1lbnQgSW5kaWNhdG9ycyAoV0RJKQoKKiBTUC5EWU4uTEUwMC5JTjogTGlmZSBleHBlY3RhbmN5IGF0IGJpcnRoLCB0b3RhbCAoeWVhcnMpCiogTlkuR0RQLlBDQVAuS0Q6IEdEUCBwZXIgY2FwaXRhIChjb25zdGFudCAyMDE1IFVTJCkKKiBTUC5QT1AuVE9UTDogUG9wdWxhdGlvbiwgdG90YWwKCmBgYHtyIGNhc2g9VFJVRX0KZGZfd2RpIDwtIFdESSgKICBjb3VudHJ5ID0gImFsbCIsIAogIGluZGljYXRvciA9IGMobGlmZUV4cCA9ICJTUC5EWU4uTEUwMC5JTiIsIHBvcCA9ICJTUC5QT1AuVE9UTCIsIGdkcFBlcmNhcCA9ICJOWS5HRFAuUENBUC5LRCIpCikKYGBgCgotLS0KCmBgYHtyfQpkZl93ZGkKYGBgCgotLS0KCmBgYHtyIGNhc2g9VFJVRX0KZGZfd2RpX2V4dHJhIDwtIFdESSgKICBjb3VudHJ5ID0gImFsbCIsIAogIGluZGljYXRvciA9IGMobGlmZUV4cCA9ICJTUC5EWU4uTEUwMC5JTiIsIHBvcCA9ICJTUC5QT1AuVE9UTCIsIGdkcFBlcmNhcCA9ICJOWS5HRFAuUENBUC5LRCIpLCAKICBleHRyYSA9IFRSVUUKKQpgYGAKCi0tLQoKYGBge3J9CmRmX3dkaV9leHRyYQpgYGAKCgotLS0KCiMjIyBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzCgojIyMjIFdoYXQgaXMgRURBIChQb3NpdCBQcmltZXJzOiBbVmlzdWFsaXNlIERhdGFdKGh0dHBzOi8vcG9zaXQuY2xvdWQvbGVhcm4vcHJpbWVycy8zLjEpKQoKMS4gRURBIGlzIGFuIGl0ZXJhdGl2ZSBjeWNsZSB0aGF0IGhlbHBzIHlvdSB1bmRlcnN0YW5kIHdoYXQgeW91ciBkYXRhIHNheXMuIFdoZW4geW91IGRvIEVEQSwgeW91OgoKMi4gR2VuZXJhdGUgcXVlc3Rpb25zIGFib3V0IHlvdXIgZGF0YQoKMy4gU2VhcmNoIGZvciBhbnN3ZXJzIGJ5IHZpc3VhbGlzaW5nLCB0cmFuc2Zvcm1pbmcsIGFuZC9vciBtb2RlbGluZyB5b3VyIGRhdGEKClVzZSB3aGF0IHlvdSBsZWFybiB0byByZWZpbmUgeW91ciBxdWVzdGlvbnMgYW5kL29yIGdlbmVyYXRlIG5ldyBxdWVzdGlvbnMKCkVEQSBpcyBhbiBpbXBvcnRhbnQgcGFydCBvZiBhbnkgZGF0YSBhbmFseXNpcy4gWW91IGNhbiB1c2UgRURBIHRvIG1ha2UgZGlzY292ZXJpZXMgYWJvdXQgdGhlIHdvcmxkOyBvciB5b3UgY2FuIHVzZSBFREEgdG8gZW5zdXJlIHRoZSBxdWFsaXR5IG9mIHlvdXIgZGF0YSwgYXNraW5nIHF1ZXN0aW9ucyBhYm91dCB3aGV0aGVyIHRoZSBkYXRhIG1lZXRzIHlvdXIgc3RhbmRhcmRzIG9yIG5vdC4KCi0tLQoKIyMjIE9wZW4gYW5kIFB1YmxpYyBEYXRhLCBXb3JsZCBCYW5rCgojIyMjIFtPcGVuIEdvdmVybm1lbnQgRGF0YSBUb29sa2l0XShodHRwOi8vb3BlbmRhdGF0b29sa2l0LndvcmxkYmFuay5vcmcpOiBbT3BlbiBEYXRhIERlZmluZWRdKGh0dHA6Ly9vcGVuZGF0YXRvb2xraXQud29ybGRiYW5rLm9yZy9lbi9lc3NlbnRpYWxzLmh0bWwpCgpUaGUgdGVybSAqKk9wZW4gRGF0YSoqIGhhcyBhIHZlcnkgcHJlY2lzZSBtZWFuaW5nLiBEYXRhIG9yIGNvbnRlbnQgaXMgb3BlbiBpZiBhbnlvbmUgaXMgZnJlZSB0byB1c2UsIHJlLXVzZSBvciByZWRpc3RyaWJ1dGUgaXQsIHN1YmplY3QgYXQgbW9zdCB0byBtZWFzdXJlcyB0aGF0IHByZXNlcnZlIHByb3ZlbmFuY2UgYW5kIG9wZW5uZXNzLgoKMS4gVGhlIGRhdGEgbXVzdCBiZSBfbGVnYWxseSBvcGVuXywgd2hpY2ggbWVhbnMgdGhleSBtdXN0IGJlIHBsYWNlZCBpbiB0aGUgcHVibGljIGRvbWFpbiBvciB1bmRlciBsaWJlcmFsIHRlcm1zIG9mIHVzZSB3aXRoIG1pbmltYWwgcmVzdHJpY3Rpb25zLgoyLiBUaGUgZGF0YSBtdXN0IGJlIF90ZWNobmljYWxseSBvcGVuXywgd2hpY2ggbWVhbnMgdGhleSBtdXN0IGJlIHB1Ymxpc2hlZCBpbiBlbGVjdHJvbmljIGZvcm1hdHMgdGhhdCBhcmUgbWFjaGluZSByZWFkYWJsZSBhbmQgbm9uLXByb3ByaWV0YXJ5LCBzbyB0aGF0IGFueW9uZSBjYW4gYWNjZXNzIGFuZCB1c2UgdGhlIGRhdGEgdXNpbmcgY29tbW9uLCBmcmVlbHkgYXZhaWxhYmxlIHNvZnR3YXJlIHRvb2xzLiBEYXRhIG11c3QgYWxzbyBiZSBwdWJsaWNseSBhdmFpbGFibGUgYW5kIGFjY2Vzc2libGUgb24gYSBwdWJsaWMgc2VydmVyLCB3aXRob3V0IHBhc3N3b3JkIG9yIGZpcmV3YWxsIHJlc3RyaWN0aW9ucy4gVG8gbWFrZSBPcGVuIERhdGEgZWFzaWVyIHRvIGZpbmQsIG1vc3Qgb3JnYW5pemF0aW9ucyBjcmVhdGUgYW5kIG1hbmFnZSBPcGVuIERhdGEgY2F0YWxvZ3MuCgotLS0KCiMjIyBXb3JsZCBCYW5rOiBXREkgLSBXb3JsZCBEZXZlbG9wbWVudCBJbmRpY2F0ZXJzCgoqIFdvcmxkIEJhbms6IGh0dHBzOi8vd3d3LndvcmxkYmFuay5vcmcKKiBbV2hvIHdlIGFyZV0oaHR0cHM6Ly93d3cud29ybGRiYW5rLm9yZy9lbi93aG8td2UtYXJlKToKICAtIFRvIGVuZCBleHRyZW1lIHBvdmVydHk6IEJ5IHJlZHVjaW5nIHRoZSBzaGFyZSBvZiB0aGUgZ2xvYmFsIHBvcHVsYXRpb24gdGhhdCBsaXZlcyBpbiBleHRyZW1lIHBvdmVydHkgdG8gMyBwZXJjZW50IGJ5IDIwMzAuCiAgLSBUbyBwcm9tb3RlIHNoYXJlZCBwcm9zcGVyaXR5OiBCeSBpbmNyZWFzaW5nIHRoZSBpbmNvbWVzIG9mIHRoZSBwb29yZXN0IDQwIHBlcmNlbnQgb2YgcGVvcGxlIGluIGV2ZXJ5IGNvdW50cnkuIAoqIFdvcmxkIEJhbmsgT3BlbiBEYXRhOiBodHRwczovL2RhdGEud29ybGRiYW5rLm9yZwogIC0gRGF0YSBCYW5rLCBXb3JsZCBEZXZlbG9wbWVudCBJbmRpY2F0b3JzLCBldGMuCiogW1dvcmxkIERldmVsb3BtZW50IEluZGljYXRvcnMgKFdESSldKGh0dHBzOi8vZGF0YXRvcGljcy53b3JsZGJhbmsub3JnL3dvcmxkLWRldmVsb3BtZW50LWluZGljYXRvcnMvKSA6IHRoZSBXb3JsZCBCYW5r4oCZcyBwcmVtaWVyIGNvbXBpbGF0aW9uIG9mIGNyb3NzLWNvdW50cnkgY29tcGFyYWJsZSBkYXRhIG9uIGRldmVsb3BtZW50OyAxNDAwIHRpbWUgc2VyaWVzIGluZGljYXRvcnMKICAtIFRoZW1lczogUG92ZXJ0eSBhbmQgSW5lcXVhbGl0eSwgUGVvcGxlLCBFbnZpcm9ubWVudCwgRWNvbm9teSwgU3RhdGVzIGFuZCBNYXJrZXRzLCBHbG9iYWwgTGlua3MKICAtIE9wZW4gRGF0YSAmIERhdGFCYW5rOiBFeHBsb3JlIGRhdGEsIFF1ZXJ5IGRhdGFiYXNlCiAgLSBCdWxrIERvd25sb2FkOiBFeGNlbCwgQ1NWCiAgLSBBUEkgRG9jdW1lbnRhdGlvbgogIAotLS0KCiMjIyBSIFBhY2thZ2UgW1dESV0oaHR0cHM6Ly9DUkFOLlItcHJvamVjdC5vcmcvcGFja2FnZT1XREkpCgoqIFtXREldKGh0dHBzOi8vQ1JBTi5SLXByb2plY3Qub3JnL3BhY2thZ2U9V0RJKTogV29ybGQgRGV2ZWxvcG1lbnQgSW5kaWNhdG9ycyBhbmQgT3RoZXIgV29ybGQgQmFuayBEYXRhCiogU2VhcmNoIGFuZCBkb3dubG9hZCBkYXRhIGZyb20gb3ZlciA0MCBkYXRhYmFzZXMgaG9zdGVkIGJ5IHRoZSBXb3JsZCBCYW5rLCBpbmNsdWRpbmcgdGhlIFdvcmxkIERldmVsb3BtZW50IEluZGljYXRvcnMgKCdXREknKSwgSW50ZXJuYXRpb25hbCBEZWJ0IFN0YXRpc3RpY3MsIERvaW5nIEJ1c2luZXNzLCBIdW1hbiBDYXBpdGFsIEluZGV4LCBhbmQgU3ViLW5hdGlvbmFsIFBvdmVydHkgaW5kaWNhdG9ycy4KKiBWZXJzaW9uOiAyLjcuNAoqIE1hdGVyaWFsczoJW1JFQURNRV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL1dESS9yZWFkbWUvUkVBRE1FLmh0bWwpICAgLSBfdXNhZ2VfCiAgLSBbTkVXU10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL1dESS9uZXdzL25ld3MuaHRtbCkgLSBfdmVyc2lvbiBoaXN0b3J5XwoqIFB1Ymxpc2hlZDogMjAyMS0wNC0wNgoqIFJFQURNRTogaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL1dESS9yZWFkbWUvUkVBRE1FLmh0bWwKKiBSZWZlcmVuY2UgbWFudWFsOglbV0RJLnBkZl0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL1dESS9XREkucGRmKQoKLS0tCgojIyMgRnVuY3Rpb24gV0RJCgoqICoqVXNhZ2UqKgoKYGBgCldESShjb3VudHJ5ID0gImFsbCIsCiAgICBpbmRpY2F0b3IgPSAiTlkuR0RQLlBDQVAuS0QiLAogICAgc3RhcnQgPSAxOTYwLAogICAgZW5kID0gMjAyMCwKICAgIGV4dHJhID0gRkFMU0UsCiAgICBjYWNoZSA9IE5VTEwpCmBgYAoKKiAqKkFyZ3VtZW50cyoqIFNlZSBIZWxwIQogIC0gY291bnRyeTogVmVjdG9yIG9mIGNvdW50cmllcyAoSVNPLTIgY2hhcmFjdGVyIGNvZGVzLCBlLmcuICJCUiIsICJVUyIsICJDQSIsIG9yICJhbGwiKSAKICAtIGluZGljYXRvcjogSWYgeW91IHN1cHBseSBhIG5hbWVkIHZlY3RvciwgdGhlIGluZGljYXRvcnMgd2lsbCBiZSBhdXRvbWF0aWNhbGx5IHJlbmFtZWQ6IGBjKCd3b21lbl9wcml2YXRlX3NlY3RvcicgPSAnQkkuUFdLLlBSVlMuRkUuWlMnKWAKCi0tLQoKIyMjIEZ1bmN0aW9uIFdESXNlYXJjaAoKYGBge3J9CmxpYnJhcnkoV0RJKQpgYGAKYGBge3J9CldESXNlYXJjaChzdHJpbmcgPSAiTlkuR0RQLlBDQVAuS0QiLCAKICAgICAgICAgIGZpZWxkID0gImluZGljYXRvciIsIGNhY2hlID0gTlVMTCkKYGBgCgotLS0KCmBgYHtyfQpXRElzZWFyY2goc3RyaW5nID0gInBvcHVsYXRpb24iLCAKICAgICAgICAgIGZpZWxkID0gIm5hbWUiLCBzaG9ydD1GQUxTRSwgY2FjaGUgPSBOVUxMKQpgYGAKCi0tLQoKYGBgCldESXNlYXJjaChzdHJpbmcgPSAiTlkuR0RQLlBDQVAuS0QiLCAKICBmaWVsZCA9ICJpbmRpY2F0b3IiLCBzaG9ydCA9IEZBTFNFLCBjYWNoZSA9IE5VTEwpCmBgYApgYGAKV0RJc2VhcmNoKHN0cmluZyA9ICJnZHAiLCAKICBmaWVsZCA9ICJuYW1lIiwgc2hvcnQgPSBUUlVFLCBjYWNoZSA9IE5VTEwpIApgYGAKCi0tLQoKIyMjIFVzZSBjYXNoCgpXRElidWxrIGRvd25sb2FkcyB0aGUgemlwIGZpbGUgb2YgQnVsayBEb3dubG9hZHMgaW4gW1dESSBzaXRlXShodHRwczovL2RhdGF0b3BpY3Mud29ybGRiYW5rLm9yZy93b3JsZC1kZXZlbG9wbWVudC1pbmRpY2F0b3JzLykgLCBpdCBpcyBhIGxpc3QgY29udGFpbmluZyA2IGRhdGEgZnJhbWVzOiBEYXRhLCBDb3VudHJ5LCBTZXJpZXMsIENvdW50cnktU2VyaWVzLCBTZXJpZXMtVGltZSwgRm9vdE5vdGUuCgpgdGltZW91dGA6IGludGVnZXIgbWF4aW11bSBudW1iZXIgb2Ygc2Vjb25kcyB0byB3YWl0IGZvciBkb3dubG9hZAoKCgpgYGB7ciBjYXNoPVRSVUV9CndkaSA8LSBXRElidWxrKHRpbWVvdXQgPSA2MDApCmBgYAotLS0KCiMjIyMgQnVsayBEb3dubG9hZHM6IERhdGEKCmBgYHtyfQp3ZGkkRGF0YSAgCmBgYAoKLS0tCgojIyMjIEJ1bGsgRG93bmxvYWRzOiBDb3VudHJ5CgpgYGB7cn0Kd2RpJENvdW50cnkgIApgYGAKCi0tLQoKIyMjIyBCdWxrIERvd25sb2FkczogU2VyaWVzCgpgYGB7cn0Kd2RpJFNlcmllcyAKYGBgCgotLS0KCiMjIyMgQnVsayBEb3dubG9hZHM6IENvdW50cnktU2VyaWVzCgpgYGB7cn0Kd2RpJGBDb3VudHJ5LVNlcmllc2AgIApgYGAKCi0tLQoKIyMjIyBCdWxrIERvd25sb2FkczogU2VyaWVzLVRpbWUKCmBgYHtyfQp3ZGkkYFNlcmllcy1UaW1lYCAgCmBgYAoKLS0tCgojIyMjIEJ1bGsgRG93bmxvYWRzOiBGb290bm90ZQoKYGBge3J9CndkaSRGb290Tm90ZSAKYGBgCgotLS0KCiMjIyBXREljYWNoZQoKRG93bmxvYWQgYW4gdXBkYXRlZCBsaXN0IG9mIGF2YWlsYWJsZSBXREkgaW5kaWNhdG9ycyBmcm9tIHRoZSBXb3JsZCBCYW5rIHdlYnNpdGUuIFJldHVybnMgYSBsaXN0IGZvciB1c2UgaW4gdGhlIFdESXNlYXJjaCBmdW5jdGlvbi4KCmBgYHtyIHdpZGNhY2hlLCBjYXNoPVRSVUV9CndkaV9jYWNoZSA8LSBXREljYWNoZSgpCmBgYAoKRG93bmxvYWRpbmcgYWxsIHNlcmllcyBpbmZvcm1hdGlvbiBmcm9tIHRoZSBXb3JsZCBCYW5rIHdlYnNpdGUgY2FuIHRha2UgdGltZS4gVGhlIFdESSBwYWNrYWdlIHNoaXBzIHdpdGggYSBsb2NhbCBkYXRhIG9iamVjdCB3aXRoIGluZm9ybWF0aW9uIG9uIGFsbCB0aGUgc2VyaWVzIGF2YWlsYWJsZSBvbiAyMDEyLTA2LTE4LiBZb3UgY2FuIHVwZGF0ZSB0aGlzIGRhdGFiYXNlIGJ5IHJldHJpZXZpbmcgYSBuZXcgbGlzdCB1c2luZyBgV0RJY2FjaGVgLCBhbmQgdGhlbiBmZWVkaW5nIHRoZSByZXN1bHRpbmcgb2JqZWN0IHRvIGBXRElzZWFyY2hgIHZpYSB0aGUgY2FjaGUgYXJndW1lbnQuCgotLS0KCmBgYHtyfQp3ZGlfY2FjaGUKYGBgCgoKLS0tCgojIyMgV0RJX2RhdGEKCkxpc3Qgb2YgMiBkYXRhIGZyYW1lcwoKVGhlIGZpcnN0IGNoYXJhY3RlciBtYXRyaXggaW5jbHVkZXMgYSBmdWxsIGxpc3Qgb2YgV0RJIHNlcmllcy4gVGhpcyBsaXN0IGlzIHVwZGF0ZWQgc2VtaS1yZWd1bGFybHkuIFVzZXJzIGNhbiByZWZyZXNoIHRoZSBsaXN0IG1hbnVhbGx5IHVzaW5nIHRoZSAnV0RJY2FjaGUoKScgZnVuY3Rpb24gYW5kIHNlYXJjaCBpbiB0aGUgdXBkYXRlZCBsaXN0IHVzaW5nIHRoZSAnY2FjaGUnIGFyZ3VtZW50LgoKCmBgYHtyfQpnbGltcHNlKFdESV9kYXRhKQpgYGAKCi0tLQoKYGBge3J9CldESV9kYXRhJHNlcmllcwpgYGAKCi0tLQoKYGBge3J9CldESV9kYXRhJGNvdW50cnkKYGBgCgpgYGB7cn0KV0RJX2RhdGEkY291bnRyeSAgJT4lIGZpbHRlcihjb3VudHJ5ID09ICJKYXBhbiIpCmBgYAoKLS0tCgpgYGB7cn0KV0RJc2VhcmNoKHN0cmluZyA9ICJnZHAiLCAKICBmaWVsZCA9ICJuYW1lIiwgc2hvcnQgPSBGQUxTRSwgY2FjaGUgPSB3ZGlfY2FjaGUpIApgYGAKCi0tLQoKIyMjIFdvcmxkIERldmVsb3BtZW50IEluZGljYXRvcnMgLSBTdW1tYXJ5CgpGaW5kIGluZGljYXRvcnM6CgoxLiBgV0RJc2VhcmNoKHN0cmluZyA9ICJnZHAiLCBmaWVsZCA9ICJuYW1lIiwgc2hvcnQgPSBGQUxTRSwgY2FjaGUgPSBOVUxMKWAKICAtIGBXRElzZWFyY2goc3RyaW5nID0gImdkcCIsIGZpZWxkID0gIm5hbWUiLCBzaG9ydCA9IEZBTFNFLCBjYWNoZSA9IHdkaV9jYWNoZSlgCiAgLSBgV0RJc2VhcmNoKHN0cmluZyA9ICJOWS5HRFAuUENBUC5LRCIsIGZpZWxkID0gImluZGljYXRvciIsIHNob3J0ID0gRkFMU0UsIGNhY2hlID0gTlVMTClgCjIuIFtXREldKGh0dHBzOi8vZGF0YXRvcGljcy53b3JsZGJhbmsub3JnL3dvcmxkLWRldmVsb3BtZW50LWluZGljYXRvcnMvKTogRGF0YSBUaGVtZXMKMy4gQnJvd3NlIGJ5IEluZGljYXRvcnM6IGh0dHBzOi8vZGF0YS53b3JsZGJhbmsub3JnL2luZGljYXRvcgogICAtIEZlYXR1cmVkIEluZGljYXRvcnMgb3IgQWxsIEluZGljYXRvcnMKICAgLSBPYnRhaW4gdGhlIGluZGljYXRvciBmcm9tIHRoZSBkZXRhaWwgb3IgdGhlIFVSTAoKLS0tCgojIyMjIEV4YW1wbGU6IENPMiBlbWlzc2lvbnMgKG1ldHJpYyB0b25zIHBlciBjYXBpdGEpCgoqIElEOiBFTi5BVE0uQ08yRS5QQwoqIFVSTDogaHR0cHM6Ly9kYXRhLndvcmxkYmFuay5vcmcvaW5kaWNhdG9yL0VOLkFUTS5DTzJFLlBDCgpgYGB7cn0KV0RJc2VhcmNoKHN0cmluZyA9ICJFTi5BVE0uQ08yRS5QQyIsIGZpZWxkID0gImluZGljYXRvciIsIAogICAgICAgICAgc2hvcnQgPSBGQUxTRSwgY2FjaGUgPSB3ZGlfY2FjaGUpCmBgYAoKYGBge3J9CldESXNlYXJjaChzdHJpbmcgPSAiRU4uQVRNLkNPMkUuUEMiLCBmaWVsZCA9ICJpbmRpY2F0b3IiLCAKICAgICAgICAgIHNob3J0ID0gRkFMU0UsIGNhY2hlID0gd2RpX2NhY2hlKSAlPiUgcHVsbChkZXNjcmlwdGlvbikKYGBgCgoqIFNvdXJjZTogQ2xpbWF0ZSBXYXRjaC4gMjAyMC4gR0hHIEVtaXNzaW9ucy4gV2FzaGluZ3RvbiwgREM6IFdvcmxkIFJlc291cmNlcyBJbnN0aXR1dGUuIEF2YWlsYWJsZSBhdDogY2xpbWF0ZXdhdGNoZGF0YS5vcmcvZ2hnLWVtaXNzaW9ucy4gU2VlIFNQLlBPUC5UT1RMIGZvciB0aGUgZGVub21pbmF0b3IncyBzb3VyY2UuCgoKCgotLS0KCmBgYHtyIGNhc2g9VFJVRX0KY28ycGNhcCA8LSBXREkoY291bnRyeSA9ICJhbGwiLCBpbmRpY2F0b3IgPSAiRU4uQVRNLkNPMkUuUEMiLCBzdGFydCA9IDE5NjAsIGVuZCA9IE5VTEwsIGV4dHJhID0gVFJVRSwgY2FjaGUgPSB3ZGlfY2FjaGUpCmBgYAoKYGBge3J9CmNvMnBjYXAKYGBgCgoKCgotLS0KCmBgYHtyfQpjbzJwY2FwICU+JSBmaWx0ZXIoY291bnRyeSAlaW4lIGMoIldvcmxkIiwgIkphcGFuIiwgIlVuaXRlZCBTdGF0ZXMiLCAiQ2hpbmEiKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IEVOLkFUTS5DTzJFLlBDLCBjb2xvciA9IGNvdW50cnkpKSArIAogIGdlb21fcG9pbnQoKSArIGdlb21fbGluZSgpCmBgYAoKLS0tCgpgYGB7cn0KY28ycGNhcCAlPiUgZmlsdGVyKCFpcy5uYShFTi5BVE0uQ08yRS5QQykpICU+JSBwdWxsKHllYXIpICU+JSBzdW1tYXJ5KCkKYGBgCgoKCgotLS0KCmBgYHtyfQpjbzJwY2FwICU+JSAKICBmaWx0ZXIoY291bnRyeSAlaW4lIGMoIldvcmxkIiwgIkphcGFuIiwgIlVuaXRlZCBTdGF0ZXMiLCAiQ2hpbmEiKSwgeWVhciAlaW4lIDE5OTA6MjAxOSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IEVOLkFUTS5DTzJFLlBDLCBjb2xvciA9IGNvdW50cnkpKSArIAogIGdlb21fcG9pbnQoKSArIGdlb21fbGluZSgpCmBgYAoKLS0tCgpgYGB7cn0KY28ycGNhcCAlPiUgCiAgZmlsdGVyKGluY29tZSAhPSAiQWdncmVnYXRlcyIsIHllYXIgPT0gMjAxOSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gaW5jb21lLCB5ID0gRU4uQVRNLkNPMkUuUEMsIGZpbGwgPSBpbmNvbWUpKSArIAogIGdlb21fYm94cGxvdCgpCmBgYAoKLS0tCgpgYGB7cn0KY28ycGNhcCAlPiUgCiAgZmlsdGVyKGluY29tZSAhPSAiQWdncmVnYXRlcyIsIHllYXIgPT0gMjAxOSwgIWlzLm5hKEVOLkFUTS5DTzJFLlBDKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gaW5jb21lLCB5ID0gRU4uQVRNLkNPMkUuUEMsIGZpbGwgPSBpbmNvbWUpKSArIAogIGdlb21fYm94cGxvdCgpCmBgYAoKKiBXaGF0IGlzIGBib3hwbG90YDogaHR0cHM6Ly92aW1lby5jb20vMjIyMzU4MDM0CgotLS0KCmBgYHtyfQpjbzJwY2FwICU+JSAKICBmaWx0ZXIoaW5jb21lICE9ICJBZ2dyZWdhdGVzIiwgeWVhciA9PSAyMDE5LCAhaXMubmEoRU4uQVRNLkNPMkUuUEMpKSAlPiUKICBncm91cF9ieShpbmNvbWUpICU+JQogIHN1bW1hcml6ZShtaW4gPSBtaW4oRU4uQVRNLkNPMkUuUEMpLCBtZWQgPSBtZWRpYW4oRU4uQVRNLkNPMkUuUEMpLCBtYXggPSBtYXgoRU4uQVRNLkNPMkUuUEMpLCBJUVIgPSBJUVIoRU4uQVRNLkNPMkUuUEMpLCBuID0gbigpKQpgYGAKCi0tLQpgYGB7cn0KY28ycGNhcCAlPiUgCiAgZmlsdGVyKGluY29tZSAhPSAiQWdncmVnYXRlcyIsIHllYXIgPT0gMjAxOSwgIWlzLm5hKEVOLkFUTS5DTzJFLlBDKSkgJT4lCiAgZmlsdGVyKCFpbmNvbWUgJWluJSBjKCJIaWdoIGluY29tZSIsICJMb3cgaW5jb21lIiwgIkxvd2VyIG1pZGRsZSBpbmNvbWUiLCAiVXBwZXIgbWlkZGxlIGluY29tZSIpKQpgYGAKCmBgYHtyfQpjbzJwY2FwICU+JSAKICBmaWx0ZXIoaW5jb21lICE9ICJBZ2dyZWdhdGVzIiwgeWVhciA9PSAyMDE5KSAlPiUKICBmaWx0ZXIoaW5jb21lID09ICJOb3QgY2xhc3NpZmllZCIpCmBgYAoKLS0tCgpgYGB7ciBlY2hvPUZBTFNFfQpjbzJwY2FwICU+JSAKICBmaWx0ZXIoaW5jb21lICE9ICJBZ2dyZWdhdGVzIiwgeWVhciA9PSAyMDE5KSAlPiUKICBnZ3Bsb3QoYWVzKG1hcF9pZCA9IGNvdW50cnkpKSArIAogIGdlb21fbWFwKGFlcyhmaWxsID0gaW5jb21lKSwgbWFwID0gd29ybGRfbWFwKSArIGV4cGFuZF9saW1pdHMoeCA9IHdvcmxkX21hcCRsb25nLCB5ID0gd29ybGRfbWFwJGxhdCkgKwogIGxhYnModGl0bGUgPSAiSW5jb21lIExldmVscyBpbiAyMDE5IikKYGBgCgotLS0KCmBgYHtyfQpjbzJwY2FwICU+JSBkaXN0aW5jdChjb3VudHJ5KQpgYGAKCi0tLQoKYGBge3J9CndvcmxkX21hcCAlPiUgZGlzdGluY3QocmVnaW9uKQpgYGAKCgpgYGB7cn0Kd29ybGRfbWFwMCA8LSB3b3JsZF9tYXAgJT4lIAogIG11dGF0ZShyZWdpb24gPSBjYXNlX3doZW4ocmVnaW9uID09ICJNYWNlZG9uaWEiIH4gIk5vcnRoIE1hY2Vkb25pYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdpb24gPT0gIkl2b3J5IENvYXN0IiAgfiAiQ290ZSBkJ0l2b2lyZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdpb24gPT0gIkRlbW9jcmF0aWMgUmVwdWJsaWMgb2YgdGhlIENvbmdvIiAgfiAiQ29uZ28sIERlbS4gUmVwLiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdpb24gPT0gIlJlcHVibGljIG9mIENvbmdvIiB+ICAiQ29uZ28sIFJlcC4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJVSyIgfiAgIlVuaXRlZCBLaW5nZG9tIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ2lvbiA9PSAiVVNBIiB+ICAiVW5pdGVkIFN0YXRlcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdpb24gPT0gIkxhb3MiIH4gICJMYW8gUERSIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ2lvbiA9PSAiU2xvdmFraWEiIH4gICJTbG92YWsgUmVwdWJsaWMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJTYWludCBMdWNpYSIgfiAgIlN0LiBMdWNpYSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdpb24gPT0gIkt5cmd5enN0YW4iICB+ICAiS3lyZ3l6IFJlcHVibGljIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ2lvbiA9PSAiTWljcm9uZXNpYSIgfiAiTWljcm9uZXNpYSwgRmVkLiBTdHMuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ2lvbiA9PSAiU3dhemlsYW5kIiAgfiAiRXN3YXRpbmkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ2lvbiA9PSAiVmlyZ2luIElzbGFuZHMiICB+ICJWaXJnaW4gSXNsYW5kcyAoVS5TLikiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ2lvbiA9PSAiUnVzc2lhIiB+ICJSdXNzaWFuIEZlZGVyYXRpb24iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ2lvbiA9PSAiRWd5cHQiIH4gIkVneXB0LCBBcmFiIFJlcC4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJTb3V0aCBLb3JlYSIgfiAiS29yZWEsIFJlcC4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJOb3J0aCBLb3JlYSIgfiAiS29yZWEsIERlbS4gUGVvcGxlJ3MgUmVwLiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdpb24gPT0gIklyYW4iIH4gIklyYW4sIElzbGFtaWMgUmVwLiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdpb24gPT0gIkJydW5laSIgfiAiQnJ1bmVpIERhcnVzc2FsYW0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJWZW5lenVlbGEiIH4gIlZlbmV6dWVsYSwgUkIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJZZW1lbiIgfiAiWWVtZW4sIFJlcC4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJCYWhhbWFzIiB+ICJCYWhhbWFzLCBUaGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJTeXJpYSIgfiAiU3lyaWFuIEFyYWIgUmVwdWJsaWMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJUdXJrZXkiIH4gIlR1cmtpeWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVnaW9uID09ICJDYXBlIFZlcmRlIiB+ICJDYWJvIFZlcmRlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZ2lvbiA9PSAiR2FtYmlhIiB+ICJHYW1iaWEsIFRoZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWdpb24gPT0gIkN6ZWNoIFJlcHVibGljIiB+ICJDemVjaGlhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiByZWdpb24pKQpgYGAKCi0tLQoKCgpgYGB7cn0KY28ycGNhcCAlPiUgZmlsdGVyKGluY29tZSAhPSAiQWdncmVnYXRlcyIsIHllYXIgPT0gMjAxOSkgJT4lIAogIGFudGlfam9pbih3b3JsZF9tYXAwLCBieSA9IGMoImNvdW50cnkiPSJyZWdpb24iKSkKYGBgCgotLS0KCmBgYHtyfQp3b3JsZF9tYXAwICU+JSBhbnRpX2pvaW4oY28ycGNhcCwgYnkgPSBjKCJyZWdpb24iPSJjb3VudHJ5IikpICU+JSBkaXN0aW5jdChyZWdpb24pICU+JSBhcnJhbmdlKHJlZ2lvbikKYGBgCgotLS0KCgoKYGBge3J9CndvcmxkX21hcDAgJT4lIGxlZnRfam9pbihpc28zMTY2LCBieSA9IGMoInJlZ2lvbiIgPSAiSVNPbmFtZSIpKSAlPiUKICBmaWx0ZXIoaXMubmEoYTIpKSAlPiUgZGlzdGluY3QocmVnaW9uKQpgYGAKCgpgYGB7cn0Kd29ybGRfbWFwIDwtIG1hcF9kYXRhKCJ3b3JsZCIpCmNvMnBjYXAgJT4lIGZpbHRlcihpbmNvbWUgIT0gIkFnZ3JlZ2F0ZXMiLCB5ZWFyID09IDIwMTkpICU+JQogIGFudGlfam9pbih3b3JsZF9tYXAsIGJ5ID0gYygiY291bnRyeSI9InJlZ2lvbiIpKQpgYGAKCgpgYGB7ciBlY2hvPUZBTFNFfQpjbzJwY2FwICU+JSAKICBmaWx0ZXIoaW5jb21lICE9ICJBZ2dyZWdhdGVzIiwgeWVhciA9PSAyMDE5KSAlPiUKICBnZ3Bsb3QoYWVzKG1hcF9pZCA9IGNvdW50cnkpKSArIAogIGdlb21fbWFwKGFlcyhmaWxsID0gaW5jb21lKSwgbWFwID0gd29ybGRfbWFwMCkgKyBleHBhbmRfbGltaXRzKHggPSB3b3JsZF9tYXAkbG9uZywgeSA9IHdvcmxkX21hcCRsYXQpICsKICBsYWJzKHRpdGxlID0gIkluY29tZSBMZXZlbHMgaW4gMjAxOSIpCmBgYAoKYGBge3J9CndvcmxkX21hcCAlPiUgZGlzdGluY3QocmVnaW9uKQpgYGAKCi0tLQoKIyMgRGF0YSBWaXN1YWxpemF0aW9uIGFuZCBgZ2dwbG90MicKCgojIyMgTGVhcm5pbmcgUmVzb3VjZXMKCiogUG9zaXQgUHJpbWVyczoKICAtIFtWaXN1YWxpemUgRGF0YV0oaHR0cHM6Ly9wb3NpdC5jbG91ZC9sZWFybi9wcmltZXJzLzMpOiBMZWFybiBob3cgdG8gdXNlIGdncGxvdDIgdG8gbWFrZSBhbnkgdHlwZSBvZiBwbG90IHdpdGggeW91ciBkYXRhLiBUaGVuIGxlYXJuIHRoZSBiZXN0IHdheXMgdG8gdmlzdWFsaXplIHBhdHRlcm5zIHdpdGhpbiB2YWx1ZXMgYW5kIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB2YXJpYWJsZXMuCiogW3I0ZHM6IERhdGEgVmlzdWFsaXphdGlvbl0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei9kYXRhLXZpc3VhbGlzYXRpb24uaHRtbCNkYXRhLXZpc3VhbGlzYXRpb24pCgotLS0KCiMjIyBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzCgojIyMjIFdoYXQgaXMgRURBPwoKRURBIGlzIGFuIGl0ZXJhdGl2ZSBjeWNsZSB0aGF0IGhlbHBzIHlvdSB1bmRlcnN0YW5kIHdoYXQgeW91ciBkYXRhIHNheXMuIFdoZW4geW91IGRvIEVEQSwgeW91OgoKMS4gR2VuZXJhdGUgcXVlc3Rpb25zIGFib3V0IHlvdXIgZGF0YQoKMi4gU2VhcmNoIGZvciBhbnN3ZXJzIGJ5IHZpc3VhbGlzaW5nLCB0cmFuc2Zvcm1pbmcsIGFuZC9vciBtb2RlbGluZyB5b3VyIGRhdGEKCjMuIFVzZSB3aGF0IHlvdSBsZWFybiB0byByZWZpbmUgeW91ciBxdWVzdGlvbnMgYW5kL29yIGdlbmVyYXRlIG5ldyBxdWVzdGlvbnMKCkVEQSBpcyBhbiBpbXBvcnRhbnQgcGFydCBvZiBhbnkgZGF0YSBhbmFseXNpcy4gWW91IGNhbiB1c2UgRURBIHRvIG1ha2UgZGlzY292ZXJpZXMgYWJvdXQgdGhlIHdvcmxkOyBvciB5b3UgY2FuIHVzZSBFREEgdG8gZW5zdXJlIHRoZSBxdWFsaXR5IG9mIHlvdXIgZGF0YSwgYXNraW5nIHF1ZXN0aW9ucyBhYm91dCB3aGV0aGVyIHRoZSBkYXRhIG1lZXRzIHlvdXIgc3RhbmRhcmRzIG9yIG5vdC4KCi0tLQoKIyMjIyBUd28gdXNlZnVsIHF1ZXN0aW9ucwoKVGhlcmUgaXMgbm8gcnVsZSBhYm91dCB3aGljaCBxdWVzdGlvbnMgeW91IHNob3VsZCBhc2sgdG8gZ3VpZGUgeW91ciByZXNlYXJjaC4gSG93ZXZlciwgdHdvIHR5cGVzIG9mIHF1ZXN0aW9ucyB3aWxsIGFsd2F5cyBiZSB1c2VmdWwgZm9yIG1ha2luZyBkaXNjb3ZlcmllcyB3aXRoaW4geW91ciBkYXRhLiBZb3UgY2FuIGxvb3NlbHkgd29yZCB0aGVzZSBxdWVzdGlvbnMgYXM6CgoxLiBXaGF0IHR5cGUgb2YgdmFyaWF0aW9uIG9jY3VycyB3aXRoaW4gbXkgdmFyaWFibGVzPwoyLiBXaGF0IHR5cGUgb2YgY292YXJpYXRpb24gb2NjdXJzIGJldHdlZW4gbXkgdmFyaWFibGVzPwoKVGhlIHJlc3Qgb2YgdGhpcyB0dXRvcmlhbCB3aWxsIGxvb2sgYXQgdGhlc2UgdHdvIHF1ZXN0aW9ucy4gVG8gbWFrZSB0aGUgZGlzY3Vzc2lvbiBlYXNpZXIsIGxldOKAmXMgZGVmaW5lIHNvbWUgdGVybXPigKYKCi0tLQoKIyMjIERhdGEgVmlzdWFsaXphdGlvbgoKIyMjIGBnZ3Bsb3QyYCBCYXNpY3MKCiFbdmlzdWFsaXphdGlvbl0oZGF0YS92aXN1YWxpemF0aW9uLnBuZykKCi0tLQoKIyMjIEV4YW1wbGU6IFdvcmxkIEluZXF1aWxpdHkgUmVwb3J0IC0gV0lSMjAyMgoKKiBXb3JsZCBJbmVxdWFsaXR5IFJlcG9ydDogaHR0cHM6Ly93aXIyMDIyLndpZC53b3JsZC8KKiBFeGVjdXRpdmUgU3VtbWFyeTogaHR0cHM6Ly93aXIyMDIyLndpZC53b3JsZC9leGVjdXRpdmUtc3VtbWFyeS8KKiBNZXRob2RvbG9neTogaHR0cHM6Ly93aXIyMDIyLndpZC53b3JsZC9tZXRob2RvbG9neS8KKiBEYXRhIFVSTDogaHR0cHM6Ly93aXIyMDIyLndpZC53b3JsZC93d3ctc2l0ZS91cGxvYWRzLzIwMjIvMDMvV0lSMjAyMlRhYmxlc0ZpZ3VyZXMtU3VtbWFyeS54bHN4CgpgYGB7cn0KbGlicmFyeShyZWFkeGwpCmBgYAoKYGBge3Igc3VtbWFyeS1kYXRhLCBjYXNoID0gVFJVRSwgZXZhbCA9IEZBTFNFfQp1cmxfc3VtbWFyeSA8LSAiaHR0cHM6Ly93aXIyMDIyLndpZC53b3JsZC93d3ctc2l0ZS91cGxvYWRzLzIwMjIvMDMvV0lSMjAyMlRhYmxlc0ZpZ3VyZXMtU3VtbWFyeS54bHN4Igpkb3dubG9hZC5maWxlKHVybCA9IHVybF9zdW1tYXJ5LCBkZXN0ZmlsZSA9ICJkYXRhL1dJUjIwMjJzLnhsc3giKSAKZXhjZWxfc2hlZXRzKCJkYXRhL1dJUjIwMjJzLnhsc3giKQpgYGAKCiMjIyBGMTQ6IEdsb2JhbCBjYXJib24gaW5lcXVhbGl0eSwgMjAxOS4gR3JvdXAgY29udHJpYnV0aW9uIHRvIHdvcmxkIGVtaXNzaW9ucyAoJSkKCk5vdGUgdGhhdCB0aGUgc2hlZXQgbmFtZSBvZiBGMTQgaGFzIHBlcmlvZCBhdCB0aGUgZW5kLiAKCmBgYHtyIGRhdGEtZjE0LCBjYXNoID0gVFJVRX0KZGZfZjE0IDwtIHJlYWRfZXhjZWwoImRhdGEvV0lSMjAyMnMueGxzeCIsIHNoZWV0ID0gImRhdGEtRjE0LiIpCmRmX2YxNApgYGAKCiogYFxuYCBmb3IgbGluZSBicmVhayBpbiB0aGUgdGl0bGUuCgotLS0KCiMjIyMgQ2F0ZWdvcmljYWwgdnMgQ29udGludW91cyBWYWx1ZQoKYGBge3J9CmRmX2YxNCAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gR3JvdXAsIHkgPSBTaGFyZSkpICsKICBnZW9tX2NvbCgpCmBgYAoKLS0tCgpgYGB7cn0KZGZfZjE0ICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBHcm91cCwgeSA9IFNoYXJlKSkgKwogIGdlb21fY29sKHdpZHRoID0gMC41LCBmaWxsID0gc2NhbGVzOjpodWVfcGFsKCkoMSlbMV0pICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwogIGxhYnModGl0bGUgPSAiRmlndXJlIDE0LiBHbG9iYWwgY2FyYm9uIGluZXF1YWxpdHksIFxuMjAxOSBHcm91cCBjb250cmlidXRpb24gdG8gd29ybGQgZW1pc3Npb25zICglKSIsIAogICAgICAgeCA9ICIiLCB5ID0gIlNoYXJlIG9mIHdvcmxkIGVtaXNzaW9ucyAoJSkiKQpgYGAKCi0tLQoKIyMjIyBNZW1vCgoqIGB3aWR0aCA9IDAuNWA6IHdpZHRoIG9mIGJhcnMKKiBgZmlsbCA9IHNjYWxlczo6aHVlX3BhbCgpKDEpWzFdKWA6IGh1ZSBzY2FsZQogIC0gaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL3NjYWxlX2h1ZS5odG1sLgoqIGBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKWA6IHBlcmNlbnQgZm9ybWF0CiAgLSBpZiBhY2N1cmFjeSA9IDAuMSwgd2UgaGF2ZSAxMC4wJSBldGMuCiogYGxhYnModGl0bGUgPSAiRmlndXJlIDE0LiBHbG9iYWwgY2FyYm9uIGluZXF1YWxpdHksIFxuMjAxOSBHcm91cCBjb250cmlidXRpb24gdG8gd29ybGQgZW1pc3Npb25zICglKSIsCiAgIHggPSAiIiwgeSA9ICJTaGFyZSBvZiB3b3JsZCBlbWlzc2lvbnMgKCUpIilgCiAgLSB0aXRsZSA9ICIiOiBgXG5gIGlzIGZvciBsaW5lIGZlZWQKICAtIHgsIHk6IGxhYmVscyBvZiB4LWF4aXMgYW5kIHktYXhpcwoKLS0tCgojIyMgRjEyOiBGZW1hbGUgc2hhcmUgaW4gZ2xvYmFsIGxhYm9yIGluY29tZXMsIDE5OTAtMjAyMAoKYGBge3IgZGF0YS1mMTIsIGNhc2ggPSBUUlVFfQpkZl9mMTIgPC0gcmVhZF9leGNlbCgiZGF0YS9XSVIyMDIycy54bHN4Iiwgc2hlZXQgPSAiZGF0YS1GMTIiKQpkZl9mMTIKYGBgCgotLS0KCmBgYHtyfQpkZl9mMTIgJT4lIAogIHNlbGVjdCh5ZWFyID0gIkRhdGEgbmVlZHMgdG8gYmUgdXBkYXRlZCIsIHZhbHVlID0gLi4uMikgJT4lCiAgZmlsdGVyKCFpcy5uYSh5ZWFyKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IHZhbHVlKSkgKwogIGdlb21fY29sKHdpZHRoID0gMC41LCBmaWxsID0gc2NhbGVzOjpodWVfcGFsKCkoMilbMl0pCmBgYAoKLS0tCgpgYGB7cn0KZGZfZjEyICU+JSAKICBzZWxlY3QoeWVhciA9ICJEYXRhIG5lZWRzIHRvIGJlIHVwZGF0ZWQiLCB2YWx1ZSA9IC4uLjIpICU+JQogIGZpbHRlcighaXMubmEoeWVhcikpICU+JQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSB2YWx1ZSkpICsKICBnZW9tX2NvbCh3aWR0aCA9IDAuNSwgZmlsbCA9IHNjYWxlczo6aHVlX3BhbCgpKDIpWzJdKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMC41LCBsaW5ldHlwZSA9IDIsIGNvbG91ciA9IHNjYWxlczo6aHVlX3BhbCgpKDIpWzFdKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwogIGxhYnModGl0bGUgPSAiRmlndXJlIDEyLiBGZW1hbGUgc2hhcmUgaW4gZ2xvYmFsIGxhYm9yIGluY29tZXMsIDE5OTAtMjAyMCIsIAogICAgICAgIHggPSAiIiwgeSA9ICIiKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMSwgeSA9IDAuNDgsIGxhYmVsID0gIkdlbmRlciBwYXJpdHkiLCBzaXplID0gMykgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDUuMiwgeSA9IDAuNDcsIGxhYmVsID0gc3RyaW5ncjo6c3RyX3dyYXAoIldvbWVuIG1ha2Ugb25seSAzNSUgb2YgZ2xvYmFsIGxhYm9yIGluY29tZXMsIG1lbiBtYWtlIHRoZSByZW1haW5pbmcgIDY1JS4iLCB3aWR0aCA9IDQwKSwgc2l6ZSA9IDMpCmBgYAoKCiMjIyBGMTogR2xvYmFsIGluY29tZSBhbmQgd2VhbHRoIGluZXF1YWxpdHksIDIwMjEKCmBgYHtyIGRhdGEtZjEsIGNhc2ggPSBUUlVFfQpkZl9mMSA8LSByZWFkX2V4Y2VsKCJkYXRhL1dJUjIwMjJzLnhsc3giLCBzaGVldCA9ICJkYXRhLUYxIikKZGZfZjEKYGBgCgotLS0KCmBgYHtyIGVjaG89RkFMU0V9CmRmX2YxX3JldiA8LSBkZl9mMSAlPiUgc2VsZWN0KGNhdCA9IC4uLjEsIDI6NCkgJT4lCiAgcGl2b3RfbG9uZ2VyKDI6NCwgbmFtZXNfdG8gPSAiZ3JvdXAiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKQpkZl9mMV9yZXYKYGBgCgpgYGB7cn0KZGZfZjFfcmV2ICU+JQogIGdncGxvdChhZXMoeCA9IGNhdCwgeSA9IHZhbHVlLCBmaWxsID0gZ3JvdXApKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKQpgYGAKCi0tLQoKIyMjIFJlZmVyZW5jZXMgb2YgYGdncGxvdDJgCgoqIFRleHRib29rOiBbUiBmb3IgRGF0YSBTY2llbmNlLCBEYXRhIFZpc3VhbGl6YXRpb25dKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovZGF0YS12aXN1YWxpc2F0aW9uLmh0bWwjZGF0YS12aXN1YWxpc2F0aW9uKQoKIyMjIyBSU3R1ZGlvIFByaW1lcnM6IFNlZSBSZWZlcmVuY2VzIGluIE1vb2RsZSBhdCB0aGUgYm90dG9tCgozLiAqKlZpc3VhbGl6ZSBEYXRhKioKICAtIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMKICAtIEJhciBDaGFydHMKICAtIEhpc3RvZ3JhbXMKICAtIEJveHBsb3RzIGFuZCBDb3VudHMKICAtIFNjYXR0ZXJwbG90cwogIC0gTGluZSBQbG90cwogIC0gT3ZlcnBsb3R0aW5nIGFuZCBCaWcgRGF0YQogIC0gQ3VzdG9taXplIFlvdXIgUGxvdHMKCi0tLQoKIyMgVGhlIFdlZWsgVGhyZWUgQXNzaWdubWVudCAoaW4gTW9vZGxlKQoKKipXREkgYW5kIGBnZ3Bsb3QyYCoqCgoqIENyZWF0ZSBhbiBSIE5vdGVib29rIG9mIGEgRGF0YSBBbmFseXNpcyBjb250YWluaW5nIHRoZSBmb2xsb3dpbmcgYW5kIHN1Ym1pdCB0aGUgcmVuZGVyZWQgSFRNTCBmaWxlIChlZy4gYGEzXzEyMzQ1Ni5uYi5odG1sYCkKICAxLiBjcmVhdGUgYW4gUiBOb3RlYm9vayB1c2luZyB0aGUgUiBOb3RlYm9vayBUZW1wbGF0ZSBpbiBNb29kbGUsICBzYXZlIGFzIGBhM18xMjM0NTYuUm1kYCwgCiAgMi4gd3JpdGUgeW91ciBuYW1lIGFuZCBJRCBhbmQgdGhlIGNvbnRlbnRzLCAKICAzLiBydW4gZWFjaCBjb2RlIGJsb2NrLCAKICA0LiBwcmV2aWV3IHRvIGNyZWF0ZSBgYTNfMTIzNDU2Lm5iLmh0bWxgLAogIDUuIHN1Ym1pdCAgYGEzXzEyMzQ1Ni5uYi5odG1sYCB0byBNb29kbGUuCgoxLiBDaG9vc2UgYXQgbGVhc3Qgb25lIGluZGljYXRvciBvZiBXREkKCiAgICAtIEluZm9ybWF0aW9uIG9mIHRoZSBkYXRhOiBOYW1lLCBJbmRpY2F0b3IsIERlc2NyaXB0aW9uLCBTb3VyY2UsIGV0Yy4KICAgIC0gRG93bmxvYWQgdGhlIGRhdGEgd2l0aCBgV0RJYAogICAgLSBFeHBsYWluIHdoeSB5b3UgY2hvc2UgdGhlIGluZGljYXRvcgogICAgLSBMaXN0IHF1ZXN0aW9ucyB5b3Ugd2FudCB0byBzdHVkeQoKLS0tCgoyLiBFeHBsb3JlIHRoZSBkYXRhIHVzaW5nIHZpc3VhbGl6YXRpb24KCjMuIE9ic2VydmF0aW9ucyBhbmQgZGlmZmljdWx0aWVzIGVuY291bnRlcmVkLgoKKipEdWU6KiogMjAyMy0wMS0xNiAyMzo1OTowMC4gU3VibWl0IHlvdXIgUiBOb3RlYm9vayBmaWxlIGluIE1vb2RsZSAoVGhlIFRoaXJkIEFzc2lnbm1lbnQpLiBEdWUgb24gTW9uZGF5IQoKLS0tCgo=